Setup

library(dplyr)
library(sf)
library(readr)
library(mapview)
library(Rspatialworkshop)
library(ggplot2)
library(leaflet)
library(httr)

Get flat data with coordinates

Use read_csv fromreadr package to load a .csv file I keep as part of a spatial data package that you can install with:

library(devtools)
install_github("mhweber/Rspatialworkshop")
library(Rspatialworkshop)

Then we:

  1. Read in the csv
  2. Suppress showing column types
  3. Select a subset of numerous attributes
  4. Filter a small portion of the 2700 gages in the dataset by filtering only gages with drainage areas > 500 sq miles
gages <- read_csv(system.file("extdata/Gages_flowdata.csv", package = "Rspatialworkshop"),show_col_types = FALSE) %>% dplyr::select(ID=SOURCE_FEA,LON_SITE,LAT_SITE, MeanFlowCFS=AVE, DrainAreaSqMiles=DA_SQ_MILE) %>% 
  dplyr::filter(DrainAreaSqMiles > 500)
glimpse(gages)
Rows: 539
Columns: 5
$ ID               <dbl> 14361500, 14378000, 14335000, 1…
$ LON_SITE         <dbl> -123.3178, -123.8123, -122.5956…
$ LAT_SITE         <dbl> 42.43040, 42.37900, 42.69985, 4…
$ MeanFlowCFS      <dbl> 3402.544, 2317.657, 1796.864, 7…
$ DrainAreaSqMiles <dbl> 2459, 665, 650, 698, 1610, 670,…

Make our data spatial

  • We use st_as_sf from the sf package to promote the data to a simple feature collection by:
    • passing the longitude and lattitude fields from our data to use
    • providing a coordinate reference system - we specify this using an epsg code
    • Our epsg code is for unprojected NAD83
    • We can find coordinate reference systems (CRS) easily from spatialreference.org
gages <- st_as_sf(gages, coords = c("LON_SITE", "LAT_SITE"), crs = 4269, remove = FALSE)
ggplot() + geom_sf(data=gages)

A simple interactive map using mapview

mapview(gages)

Customize mapview

  • Change the background
  • Scale the symbol size by flow rate
m <- mapview(gages, map.types = c("Esri.WorldShadedRelief", "OpenStreetMap"), color = "grey40",cex = "MeanFlowCFS")
m

Add Web Map Service (WMS) Layers!

Web Map Services provide pre-rendered map tiles at different scales and are useful as background map layers. Here is my original Stack Overflow question from when I first played with adding WMS layers with mapview and leaflet

NHD WMS from the National Map

Here we display a background of National Hydrography Dataset stream lines to go with our gages without having to load local files.

This is a super handy way to share your data in an interactive map mashed up with relevant background layers in one file in R, without having to share spatial files.

m <- mapview(gages, cex = "MeanFlowCFS")
# Define the NHD WMS service
wms_nhd <- "https://hydro.nationalmap.gov:443/arcgis/services/nhd/MapServer/WmsServer?"
m@map <- m@map %>% 
  addWMSTiles(group = 'USGS HydroCache',
              wms_nhd,layers  = 6,
              options = WMSTileOptions(format = "image/png", transparent = TRUE),
              attribution = "")  %>% mapview:::mapViewLayersControl(names = "NHD")

m

Other WMS Services

We can see other services available on the National Map here - let’s try transportation

# Define the WMS service
m <- mapview(gages, cex = "MeanFlowCFS")
wms_trails <- "https://carto.nationalmap.gov:443/arcgis/services/transportation/MapServer/WmsServer?"
m@map <- m@map %>% 
  addWMSTiles(group = 'Trails',
              wms_trails,layers  = 3,
              options = WMSTileOptions(format = "image/png", transparent = TRUE),
              attribution = "")  %>% 
  addWMSTiles(group = 'Trail Labels',
              wms_trails,layers  = 15,
              options = WMSTileOptions(format = "image/png", transparent = TRUE),
              attribution = "") %>%  mapview:::mapViewLayersControl(names = c("Trails","Trail Names"))
                                  
m

Querying and making spatial Web Feature Services (WFS)

Just to show scope of different things we can do linking to REST Services as well - here are links to a couple examples- spatial wfs services and accessing arcgis rest services

And we can also use REST services for the same WMS layers we displayed in maps above! See National Map Services page

We can get a listing of all ESRI REST services here

Query water bodies REST feature

url <- parse_url("https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services")
url$path <- paste(url$path, "USA_Water_Bodies/FeatureServer/0/query", sep = "/")
url$query <- list(where = "STATE = 'OR'",
                  outFields = "*",
                  returnGeometry = "true",
                  f = "geojson")
request <- build_url(url)


wb <- read_sf(request)

mapview(gages) + mapview(wb, col.regions='light blue')

Query trails we used earlier

This time use the REST service and a query for ‘Pacific Crest National Scenic Trail’ - bonus add a default topography brackground with it

url <- parse_url("https://carto.nationalmap.gov/arcgis/rest/services")
url$path <- paste(url$path, "transportation/MapServer/37/query", sep = "/")
url$query <- list(where = "Name = 'Pacific Crest National Scenic Trail'",
                  outFields = "*",
                  returnGeometry = "true",
                  f = "json")
request <- build_url(url)

PCT <- read_sf(request)

mapview(PCT, color='dark green',map.types = "OpenTopoMap")
LS0tDQp0aXRsZTogIlF1aWNrIE1hcHBpbmcgTGlnaHRuaW5nIFRhbGsiDQphdXRob3I6ICJNYXJjIFdlYmVyIg0KZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIHRoZW1lOiBzYW5kc3RvbmUNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgICBkZl9wcmludDogcGFnZWQNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCiMjIFNldHVwDQpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkobWFwdmlldykNCmxpYnJhcnkoUnNwYXRpYWx3b3Jrc2hvcCkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkobGVhZmxldCkNCmxpYnJhcnkoaHR0cikNCmBgYA0KDQojIyBHZXQgZmxhdCBkYXRhIHdpdGggY29vcmRpbmF0ZXMNClVzZSBgcmVhZF9jc3ZgIGZyb21gcmVhZHJgIHBhY2thZ2UgdG8gbG9hZCBhIC5jc3YgZmlsZSBJIGtlZXAgYXMgcGFydCBvZiBhIHNwYXRpYWwgZGF0YSBwYWNrYWdlIHRoYXQgeW91IGNhbiBpbnN0YWxsIHdpdGg6DQpgYGANCmxpYnJhcnkoZGV2dG9vbHMpDQppbnN0YWxsX2dpdGh1YigibWh3ZWJlci9Sc3BhdGlhbHdvcmtzaG9wIikNCmxpYnJhcnkoUnNwYXRpYWx3b3Jrc2hvcCkNCmBgYA0KVGhlbiB3ZToNCg0KMS4gUmVhZCBpbiB0aGUgY3N2DQoyLiBTdXBwcmVzcyBzaG93aW5nIGNvbHVtbiB0eXBlcw0KMy4gU2VsZWN0IGEgc3Vic2V0IG9mIG51bWVyb3VzIGF0dHJpYnV0ZXMNCjQuIEZpbHRlciBhIHNtYWxsIHBvcnRpb24gb2YgdGhlIDI3MDAgZ2FnZXMgaW4gdGhlIGRhdGFzZXQgYnkgZmlsdGVyaW5nIG9ubHkgZ2FnZXMgd2l0aCBkcmFpbmFnZSBhcmVhcyA+IDUwMCBzcSBtaWxlcw0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpnYWdlcyA8LSByZWFkX2NzdihzeXN0ZW0uZmlsZSgiZXh0ZGF0YS9HYWdlc19mbG93ZGF0YS5jc3YiLCBwYWNrYWdlID0gIlJzcGF0aWFsd29ya3Nob3AiKSxzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUgZHBseXI6OnNlbGVjdChJRD1TT1VSQ0VfRkVBLExPTl9TSVRFLExBVF9TSVRFLCBNZWFuRmxvd0NGUz1BVkUsIERyYWluQXJlYVNxTWlsZXM9REFfU1FfTUlMRSkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKERyYWluQXJlYVNxTWlsZXMgPiA1MDApDQpnbGltcHNlKGdhZ2VzKQ0KYGBgDQoNCiMjIE1ha2Ugb3VyIGRhdGEgc3BhdGlhbA0KDQotIFdlIHVzZSBgc3RfYXNfc2ZgIGZyb20gdGhlIGBzZmAgcGFja2FnZSB0byBwcm9tb3RlIHRoZSBkYXRhIHRvIGEgYHNpbXBsZSBmZWF0dXJlIGNvbGxlY3Rpb25gIGJ5Og0KICAgICsgcGFzc2luZyB0aGUgbG9uZ2l0dWRlIGFuZCBsYXR0aXR1ZGUgZmllbGRzIGZyb20gb3VyIGRhdGEgdG8gdXNlIA0KICAgICsgcHJvdmlkaW5nIGEgY29vcmRpbmF0ZSByZWZlcmVuY2Ugc3lzdGVtIC0gd2Ugc3BlY2lmeSB0aGlzIHVzaW5nIGFuIGBlcHNnYCBjb2RlDQogICAgKyBPdXIgYGVwc2dgIGNvZGUgaXMgZm9yIHVucHJvamVjdGVkIE5BRDgzDQogICAgKyBXZSBjYW4gZmluZCBjb29yZGluYXRlIHJlZmVyZW5jZSBzeXN0ZW1zIChDUlMpIGVhc2lseSBmcm9tIFtzcGF0aWFscmVmZXJlbmNlLm9yZ10oc3BhdGlhbHJlZmVyZW5jZS5vcmcpDQpgYGB7cn0NCmdhZ2VzIDwtIHN0X2FzX3NmKGdhZ2VzLCBjb29yZHMgPSBjKCJMT05fU0lURSIsICJMQVRfU0lURSIpLCBjcnMgPSA0MjY5LCByZW1vdmUgPSBGQUxTRSkNCmdncGxvdCgpICsgZ2VvbV9zZihkYXRhPWdhZ2VzKQ0KYGBgDQoNCiMjIEEgc2ltcGxlIGludGVyYWN0aXZlIG1hcCB1c2luZyBgbWFwdmlld2ANCmBgYHtyfQ0KbWFwdmlldyhnYWdlcykNCmBgYA0KDQojIyBDdXN0b21pemUgbWFwdmlldw0KDQotIENoYW5nZSB0aGUgYmFja2dyb3VuZA0KLSBTY2FsZSB0aGUgc3ltYm9sIHNpemUgYnkgZmxvdyByYXRlDQpgYGB7cn0NCm0gPC0gbWFwdmlldyhnYWdlcywgbWFwLnR5cGVzID0gYygiRXNyaS5Xb3JsZFNoYWRlZFJlbGllZiIsICJPcGVuU3RyZWV0TWFwIiksIGNvbG9yID0gImdyZXk0MCIsY2V4ID0gIk1lYW5GbG93Q0ZTIikNCm0NCmBgYA0KDQojIyBBZGQgV2ViIE1hcCBTZXJ2aWNlIChXTVMpIExheWVycyENCltXZWIgTWFwIFNlcnZpY2VzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9XZWJfTWFwX1NlcnZpY2UpIHByb3ZpZGUgcHJlLXJlbmRlcmVkIG1hcCB0aWxlcyBhdCBkaWZmZXJlbnQgc2NhbGVzIGFuZCBhcmUgdXNlZnVsIGFzIGJhY2tncm91bmQgbWFwIGxheWVycy4gSGVyZSBpcyBteSBvcmlnaW5hbCBbU3RhY2sgT3ZlcmZsb3cgcXVlc3Rpb25dKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzMyOTYwMDUwL2xvYWRpbmctd21zLWxheWVyLWluLXItbGVhZmxldC11c2luZy1hZGR3bXN0aWxlcykgZnJvbSB3aGVuIEkgZmlyc3QgcGxheWVkIHdpdGggYWRkaW5nIFdNUyBsYXllcnMgd2l0aCBgbWFwdmlld2AgYW5kIGBsZWFmbGV0YA0KDQojIyMgTkhEIFdNUyBmcm9tIHRoZSBOYXRpb25hbCBNYXANCkhlcmUgd2UgZGlzcGxheSBhIGJhY2tncm91bmQgb2YgTmF0aW9uYWwgSHlkcm9ncmFwaHkgRGF0YXNldCBzdHJlYW0gbGluZXMgdG8gZ28gd2l0aCBvdXIgZ2FnZXMgd2l0aG91dCBoYXZpbmcgdG8gbG9hZCBsb2NhbCBmaWxlcy4NCg0KVGhpcyBpcyBhIHN1cGVyIGhhbmR5IHdheSB0byBzaGFyZSB5b3VyIGRhdGEgaW4gYW4gaW50ZXJhY3RpdmUgbWFwIG1hc2hlZCB1cCB3aXRoIHJlbGV2YW50IGJhY2tncm91bmQgbGF5ZXJzIGluIG9uZSBmaWxlIGluIFIsIHdpdGhvdXQgaGF2aW5nIHRvIHNoYXJlIHNwYXRpYWwgZmlsZXMuDQpgYGB7cn0NCm0gPC0gbWFwdmlldyhnYWdlcywgY2V4ID0gIk1lYW5GbG93Q0ZTIikNCiMgRGVmaW5lIHRoZSBOSEQgV01TIHNlcnZpY2UNCndtc19uaGQgPC0gImh0dHBzOi8vaHlkcm8ubmF0aW9uYWxtYXAuZ292OjQ0My9hcmNnaXMvc2VydmljZXMvbmhkL01hcFNlcnZlci9XbXNTZXJ2ZXI/Ig0KbUBtYXAgPC0gbUBtYXAgJT4lIA0KICBhZGRXTVNUaWxlcyhncm91cCA9ICdVU0dTIEh5ZHJvQ2FjaGUnLA0KICAgICAgICAgICAgICB3bXNfbmhkLGxheWVycyAgPSA2LA0KICAgICAgICAgICAgICBvcHRpb25zID0gV01TVGlsZU9wdGlvbnMoZm9ybWF0ID0gImltYWdlL3BuZyIsIHRyYW5zcGFyZW50ID0gVFJVRSksDQogICAgICAgICAgICAgIGF0dHJpYnV0aW9uID0gIiIpICAlPiUgbWFwdmlldzo6Om1hcFZpZXdMYXllcnNDb250cm9sKG5hbWVzID0gIk5IRCIpDQoNCm0NCmBgYA0KDQojIyMgT3RoZXIgV01TIFNlcnZpY2VzDQpXZSBjYW4gc2VlIG90aGVyIHNlcnZpY2VzIGF2YWlsYWJsZSBvbiB0aGUgTmF0aW9uYWwgTWFwIFtoZXJlXShodHRwczovL2FwcHMubmF0aW9uYWxtYXAuZ292L3NlcnZpY2VzLykgLSBsZXQncyB0cnkgdHJhbnNwb3J0YXRpb24NCmBgYHtyfQ0KIyBEZWZpbmUgdGhlIFdNUyBzZXJ2aWNlDQptIDwtIG1hcHZpZXcoZ2FnZXMsIGNleCA9ICJNZWFuRmxvd0NGUyIpDQp3bXNfdHJhaWxzIDwtICJodHRwczovL2NhcnRvLm5hdGlvbmFsbWFwLmdvdjo0NDMvYXJjZ2lzL3NlcnZpY2VzL3RyYW5zcG9ydGF0aW9uL01hcFNlcnZlci9XbXNTZXJ2ZXI/Ig0KbUBtYXAgPC0gbUBtYXAgJT4lIA0KICBhZGRXTVNUaWxlcyhncm91cCA9ICdUcmFpbHMnLA0KICAgICAgICAgICAgICB3bXNfdHJhaWxzLGxheWVycyAgPSAzLA0KICAgICAgICAgICAgICBvcHRpb25zID0gV01TVGlsZU9wdGlvbnMoZm9ybWF0ID0gImltYWdlL3BuZyIsIHRyYW5zcGFyZW50ID0gVFJVRSksDQogICAgICAgICAgICAgIGF0dHJpYnV0aW9uID0gIiIpICAlPiUgDQogIGFkZFdNU1RpbGVzKGdyb3VwID0gJ1RyYWlsIExhYmVscycsDQogICAgICAgICAgICAgIHdtc190cmFpbHMsbGF5ZXJzICA9IDE1LA0KICAgICAgICAgICAgICBvcHRpb25zID0gV01TVGlsZU9wdGlvbnMoZm9ybWF0ID0gImltYWdlL3BuZyIsIHRyYW5zcGFyZW50ID0gVFJVRSksDQogICAgICAgICAgICAgIGF0dHJpYnV0aW9uID0gIiIpICU+JSAgbWFwdmlldzo6Om1hcFZpZXdMYXllcnNDb250cm9sKG5hbWVzID0gYygiVHJhaWxzIiwiVHJhaWwgTmFtZXMiKSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCm0NCmBgYA0KDQojIyBRdWVyeWluZyBhbmQgbWFraW5nIHNwYXRpYWwgV2ViIEZlYXR1cmUgU2VydmljZXMgKFdGUykNCkp1c3QgdG8gc2hvdyBzY29wZSBvZiBkaWZmZXJlbnQgdGhpbmdzIHdlIGNhbiBkbyBsaW5raW5nIHRvIFJFU1QgU2VydmljZXMgYXMgd2VsbCAtIGhlcmUgYXJlIGxpbmtzIHRvIGEgY291cGxlIGV4YW1wbGVzLQ0KW3NwYXRpYWwgd2ZzIHNlcnZpY2VzXShodHRwczovL2luYm8uZ2l0aHViLmlvL3R1dG9yaWFscy90dXRvcmlhbHMvc3BhdGlhbF93ZnNfc2VydmljZXMvKSBhbmQgDQpbYWNjZXNzaW5nIGFyY2dpcyByZXN0IHNlcnZpY2VzXShodHRwczovL2NvbW11bml0eS5lc3JpLmNvbS90NS9naXMtYmxvZy9hY2Nlc3NpbmctYXJjZ2lzLXJlc3Qtc2VydmljZXMtdXNpbmctci9iYS1wLzg5ODQ1MSkNCg0KQW5kIHdlIGNhbiBhbHNvIHVzZSBSRVNUIHNlcnZpY2VzIGZvciB0aGUgc2FtZSBXTVMgbGF5ZXJzIHdlIGRpc3BsYXllZCBpbiBtYXBzIGFib3ZlIQ0KU2VlIFtOYXRpb25hbCBNYXAgU2VydmljZXMgcGFnZV0oaHR0cHM6Ly9hcHBzLm5hdGlvbmFsbWFwLmdvdi9zZXJ2aWNlcy8pDQoNCldlIGNhbiBnZXQgYSBsaXN0aW5nIG9mIGFsbCBFU1JJIFJFU1Qgc2VydmljZXMgW2hlcmVdKGh0dHBzOi8vc2VydmljZXMuYXJjZ2lzLmNvbS9QM2VQTE1ZczJSVkNoa0p4L0FyY0dJUy9yZXN0L3NlcnZpY2VzKQ0KDQojIyMgUXVlcnkgd2F0ZXIgYm9kaWVzIFJFU1QgZmVhdHVyZQ0KYGBge3J9DQp1cmwgPC0gcGFyc2VfdXJsKCJodHRwczovL3NlcnZpY2VzLmFyY2dpcy5jb20vUDNlUExNWXMyUlZDaGtKeC9hcmNnaXMvcmVzdC9zZXJ2aWNlcyIpDQp1cmwkcGF0aCA8LSBwYXN0ZSh1cmwkcGF0aCwgIlVTQV9XYXRlcl9Cb2RpZXMvRmVhdHVyZVNlcnZlci8wL3F1ZXJ5Iiwgc2VwID0gIi8iKQ0KdXJsJHF1ZXJ5IDwtIGxpc3Qod2hlcmUgPSAiU1RBVEUgPSAnT1InIiwNCiAgICAgICAgICAgICAgICAgIG91dEZpZWxkcyA9ICIqIiwNCiAgICAgICAgICAgICAgICAgIHJldHVybkdlb21ldHJ5ID0gInRydWUiLA0KICAgICAgICAgICAgICAgICAgZiA9ICJnZW9qc29uIikNCnJlcXVlc3QgPC0gYnVpbGRfdXJsKHVybCkNCg0KDQp3YiA8LSByZWFkX3NmKHJlcXVlc3QpDQoNCm1hcHZpZXcoZ2FnZXMpICsgbWFwdmlldyh3YiwgY29sLnJlZ2lvbnM9J2xpZ2h0IGJsdWUnKQ0KYGBgDQoNCiMjIyBRdWVyeSB0cmFpbHMgd2UgdXNlZCBlYXJsaWVyDQpUaGlzIHRpbWUgdXNlIHRoZSBSRVNUIHNlcnZpY2UgYW5kIGEgcXVlcnkgZm9yICdQYWNpZmljIENyZXN0IE5hdGlvbmFsIFNjZW5pYyBUcmFpbCcgLSBib251cyBhZGQgYSBkZWZhdWx0IHRvcG9ncmFwaHkgYnJhY2tncm91bmQgd2l0aCBpdA0KYGBge3J9DQp1cmwgPC0gcGFyc2VfdXJsKCJodHRwczovL2NhcnRvLm5hdGlvbmFsbWFwLmdvdi9hcmNnaXMvcmVzdC9zZXJ2aWNlcyIpDQp1cmwkcGF0aCA8LSBwYXN0ZSh1cmwkcGF0aCwgInRyYW5zcG9ydGF0aW9uL01hcFNlcnZlci8zNy9xdWVyeSIsIHNlcCA9ICIvIikNCnVybCRxdWVyeSA8LSBsaXN0KHdoZXJlID0gIk5hbWUgPSAnUGFjaWZpYyBDcmVzdCBOYXRpb25hbCBTY2VuaWMgVHJhaWwnIiwNCiAgICAgICAgICAgICAgICAgIG91dEZpZWxkcyA9ICIqIiwNCiAgICAgICAgICAgICAgICAgIHJldHVybkdlb21ldHJ5ID0gInRydWUiLA0KICAgICAgICAgICAgICAgICAgZiA9ICJqc29uIikNCnJlcXVlc3QgPC0gYnVpbGRfdXJsKHVybCkNCg0KUENUIDwtIHJlYWRfc2YocmVxdWVzdCkNCg0KbWFwdmlldyhQQ1QsIGNvbG9yPSdkYXJrIGdyZWVuJyxtYXAudHlwZXMgPSAiT3BlblRvcG9NYXAiKQ0KYGBg